工厂模式All in One

工厂模式是一种较为常见的设计模式,主要用于对象的创建。

What

当我们需要处理对象间的依赖时,如当某接口的实现类对象被依赖,通常需要在代码中利用new创建对象,而其实依赖方只想调用其对象的一些方法,而不关心该对象的创建过程。
而且当代码中有多处创建了此类对象,一旦构造方法发生了变化,则需要将多处构造方法同时修改,重复劳动。
工厂模式解决的主要就是上述两个问题:

  1. 将调用方与资源解耦,调用方将资源的初始化统一交给工厂,将资源的创建与使用分离。
  2. 避免重复进行复杂对象的初始化。
    如下,我们以内存产品作为资源为例。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    interface RAM {}
    abstract class RAM8G implements RAM {
    public RAM8G() {
    System.out.println("building 8G RAM");
    }
    }
    class RAM16G implements RAM {
    public RAM16G() {
    System.out.println("building 16G RAM");
    }
    }

简单/静态工厂

静态工厂的思路是一个工厂搞定全部类似对象的请求,实现非常简单,直接将对象的创建交给工厂,由参数来区分调用方具体需要的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class StaticFactory {
private final static int SIZE_8G = 8;
private final static int SIZE_16G = 16;
public RAM createRAM(int size) {
switch(size) {
case SIZE_8G: return new RAM8G();
case SIZE_16G : return new RAM16G();
default: return null;
}
}
}
public class StaticFactoryTest {
public static void main(String[] args) {
StaticFactory factory = new StaticFactory();
RAM _8g = factory.createRAM(8);
RAM _16g = factory.createRAM(16);
}
}

也可以用静态的方式去写工厂,连工厂的实例化都省了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class StaticFactory {
...
public static RAM createRAM(int size) {
switch(size) {
case SIZE_8G: return new RAM8G();
case SIZE_16G : return new RAM16G();
default: return null;
}
}
}
public class StaticFactoryTest {
public static void main(String[] args) {
RAM _8g = StaticFactory.createRAM(8);
RAM _16g = StaticFactory.createRAM(16);
}
}

问题

  1. 当需要扩展产品时,如加一个32G的内存,需修改工厂类的createRAM方法,不符合开闭原则中的“对修改关闭”原则。
  2. 大量逻辑堆积在工厂类,难以支持创建需要额外参数的产品。

工厂方法

工厂方法模式为不同产品的相同方法创建不同的工厂,可以理解为对简单工厂的抽象,而且更加直观。

定义

根据GoF的定义,工厂方法使用继承,由子类来完成实例的初始化

实现

针对简单工厂,其实可以适当做些改进,或许我们可以使用更直观的方式来替换switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class StaticFactory {
public static RAM create8GRAM() {
return RAM8G();
}
public static RAM create16GRAM() {
return RAM16G();
}
}
public class StaticFactoryTest {
public static void main(String[] args) {
RAM _8g = StaticFactory.create8GRAM();
RAM _16g = StaticFactory.create16GRAM();
}
}

上述改进是基于方法名来区分不同产品,而工厂方法则用工厂类名来区分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface RAMFactory {
RAM createRAM();
}
class RAM8GFactory implements RAMFactory {
@Override
public RAM createRAM() {
return new RAM8G();
}
}
class RAM16GFactory implements RAMFactory {
@Override
public RAM createRAM() {
return new RAM16G();
}
}
public class FactoryMethodTest {
public static void main(String[] args) {
RAMFactory factory8G = new RAM8GFactory();
RAMFactory factory16G = new RAM16GFactory();
RAM _8g = factory8G.createRAM();
RAM _16g = factory16G.createRAM();
}
}

问题

当我们需扩展产品时,如新增一个32G的产品,需新增完整的工厂类实现,因此如果产品很多时会有很多的工厂类。

抽象工厂

当一个大类型的产品下出现多维度的细分,如8G内存可以分为DDR3和DDR4,形成等级结构,此时有产品簇的概念。

产品簇

不同等级结构中功能关联的产品,如8G内存及16G内存分为DDR3和DDR4,8G DDR3和16G DDR3就是一个产品簇的。
抽象工厂的思路是将不变的属性(分类)作为工厂。如果产品全属于单一等级结构,则退化为工厂方法模式。

定义

根据GoF的说法,在抽象工厂模式中,使用组合的方式去委派实例的创建任务

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// 产品,出现了新的维度
class RAM8GDDR3 extends RAM8G {
public RAM8GDDR3() {
System.out.println("building 8G DDR3 RAM");
}
}
class RAM8GDDR4 extends RAM8G {
public RAM8GDDR4() {
System.out.println("building 8G DDR4 RAM");
}
}
class RAM16GDDR3 extends RAM16G {
public RAM16GDDR3() {
System.out.println("building 16G DDR3 RAM");
}
}
class RAM16GDDR4 extends RAM16G {
public RAM16GDDR4() {
System.out.println("building 16G DDR4 RAM");
}
}
// 工厂
interface RAMAbsFactory() {
public RAM create8G();
public RAM create16G();
}
class RAMDDR3Factory implements RAMAbsFactory {
public RAM create8G() {
return new RAM8GDDR3();
}
public RAM create16G() {
return new RAM16GDDR3();
}
}
class RAMDDR4Factory implements RAMAbsFactory {
public RAM create8G() {
return new RAM8GDDR4();
}
public RAM create16G() {
return new RAM16GDDR4();
}
}
public class AbstractFactoryTest {
public static void main(String[] args) {
RAMDDR3Factory ddr3Factory = new RAMDDR3Factory();
RAMDDR4Factory ddr4Factory = new RAMDDR4Factory();
RAM _8GDDR3 = ddr3Factory.create8G();
RAM _8GDDR4 = ddr4Factory.create8G();
RAM _16GDDR3 = ddr3Factory.create16G();
RAM _16GDDR4 = ddr4Factory.create16G();
}
}

比较

工厂方法模式和抽象工厂模式的调用方式显得比简单工厂更直观,体现在使用方法名或类名来区分不同的产品,而不是通过调用方传的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 简单工厂
public class FooFactory {
public Foo(int withBars) {
... // 根据参数switch
}
}
// 工厂方法
public class FooFactory {
public Foo withoutBar();
public Foo withOneBar();
public Foo withTwoBars();
}
// 抽象工厂
public class NoBarFooFactory {
public Foo withBaz();
public Foo withoutBaz();
}
public class OneBarFooFactory {
public Foo withBaz();
public Foo withoutBaz();
}
public class TwoBarsFooFactory {
public Foo withBaz();
public Foo withoutBaz();
}
// 调用简单工厂
ff.foo(0);
ff.foo(1);
ff.foo(2);
// 调用工厂方法
ff.withoutBar();
ff.withOneBar();
ff.withTwoBars();
// 调用抽象工厂
noBarFF.withBaz();
noBarFF.withoutBaz();
oneBarFF.withBaz();
oneBarFF.withoutBaz();
twoBarsFF.withBaz();
twoBarsFF.withoutBaz();